home *** CD-ROM | disk | FTP | other *** search
- {
- GERD KORTEMEYER
-
- here are two Units For trapping float-exceptions. In your Program you
- will have to add
-
- Uses err387
-
- and at the beginning of your main Program say For example
-
- begin
- exception(overflow, masked);
- exception(underflow, dumpask);
- exception(invalid, dumpexit);
- autocorrect(zerodiv, 1.0);
- exception(precision, masked);
-
- In this way you can choose For any kind of exception in which way it is
- to be handeled. After the lines above the result of a division by zero
- will be '1.0', in Case of an underflow there will be a dump of the copro
- and the user will be asked For the result he wants the operation to have,
- in Case of an overflow the largest available number will be chosen and
- so on ...
-
- Here are the Units
-
- err387 and dis387
- }
-
- { ---------------------------------------------------------- }
- { Fehlerbehandlungsroutinen fuer den Intel 80387 bzw. 486 DX }
- { Geschrieben in Turbo Pascal 6.0 }
- { von Gerd Kortemeyer, Hannover }
- { ---------------------------------------------------------- }
-
- Unit err387;
-
- Interface
-
- Uses
- dis387, Dos, Crt;
-
- Const
- invalid = 1;
- denormal = 2;
- zero_div = 4;
- overflow = 8;
- underflow = 16;
- precision = 32;
- stackfault= 64;
- con1 = 512;
-
- masked = 0;
- runtime = 1;
- dump = 2;
- dumpexit = 3;
- dumpask = 4;
- autocorr = 5;
-
-
- Procedure exception(which, what : Word);
- Procedure autocorrect(which : Word; by : Extended);
-
- Procedure handle_off;
- Procedure handle_on;
-
- Procedure restore_masks;
-
- Procedure clear_copro;
- Function status_Word : Word;
-
- Var
- do_again : Word;
-
- Implementation
-
- Const
- valid = 0;
- zero = 1;
- spec = 2;
- empty = 3;
-
- topmask : Word = 14336;
- topdiv = 2048;
-
- anyerrors : Word = 63;
-
- zweipot : Array [0..15] of Word =
- (1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,
- 2048, 4096, 8192, 16384, 32768);
-
- ex_nam : Array[0..5] of String=
- ('Invalid ',
- 'Denormal ',
- 'Zero-Div ',
- 'Overflow ',
- 'Underflow ',
- 'Precision ');
-
- Var
- setmasks : Byte;
- normal : Record
- Case Boolean OF
- True : (adr : Pointer);
- False: (pro : Procedure);
- end;
-
- Exit_on,
- dump_on,
- ask_on,
- auto_on,
- standard : Word;
-
- auto_val : Array [0..5] of Extended;
-
- Procedure Mask(which : Word);
- Var
- cw : Word;
- begin
- Asm
- fstcw cw
- end;
- cw := cw or which;
- setmasks := Lo(cw);
- Asm
- fldcw cw
- end;
- end;
-
- Procedure Unmask(which : Word);
- Var
- cw : Word;
- begin
- Asm
- fclex
- fstcw cw
- end;
- cw := cw and not (which);
- setmasks := Lo(cw);
- Asm
- fldcw cw
- end;
- end;
-
- Procedure restore_masks;
- Var
- setm : Word;
- i :Integer;
- begin
- setm:=setmasks;
- For i := 0 to 5 do
- if (setm and zweipot[i]) <> 0 then
- Mask (zweipot[i])
- else
- Unmask(zweipot[i]);
- end;
-
- Procedure clear_copro;
- Var
- cw : Word;
- begin
- Asm
- fstcw cw
- end;
- setmasks := Lo(cw);
- Asm
- finit
- end;
- end;
-
- Function status_Word;
- begin
- Asm
- fstsw @result
- end;
- end;
-
- { Bei welcher Exception soll was passieren? }
- Procedure exception;
- begin
- Case what OF
-
- masked : Mask(which);
-
- runtime :
- begin
- Unmask(which);
- standard := standard or which;
- end;
-
- dump :
- begin
- Unmask(which);
- standard := standard and NOT(which);
- dump_on := dump_on or which;
- Exit_on := Exit_on and NOT(which);
- ask_on := ask_on and NOT(which);
- auto_on := auto_on and NOT(which);
- end;
-
- dumpexit :
- begin
- Unmask(which);
- standard := standard and NOT(which);
- dump_on := dump_on or which;
- Exit_on := Exit_on or which;
- ask_on := ask_on and NOT(which);
- auto_on := auto_on and NOT(which);
- end;
-
- dumpask :
- begin
- Unmask(which);
- standard := standard and NOT(which);
- dump_on := dump_on or which;
- Exit_on := Exit_on and NOT(which);
- ask_on := ask_on or which;
- auto_on := auto_on and NOT(which);
- end;
- end;
- end;
-
- { zum Setzen von Auto-Korrekt-Werten }
-
- Procedure autocorrect;
- Var
- i : Integer;
- begin
- Unmask(which);
- standard := standard and NOT(which);
- dump_on := dump_on and NOT(which);
- Exit_on := Exit_on and NOT(which);
- ask_on := ask_on and NOT(which);
- auto_on := auto_on or which;
- For i := 0 to 5 do
- if (which and zweipot[i]) <> 0 then
- auto_val[i] := by;
- end;
-
- { ------------- Die Interrupt-Routine selbst ------------- }
-
- Procedure errorcon; Interrupt;
- Var
- copro : Record
- control_Word,
- status_Word,
- tag_Word, op,
- instruction_Pointer,
- ip, operand_Pointer, : Word;
- st : Array [0..7] of Extended;
- end;
-
- top : Integer; { welches Register ist Stacktop? }
-
- masked, { welche Exceptions maskiert? }
- occured : Byte; { welche Exceptions aufgetreten? }
-
- opcode : Word;
-
- inst_seg, { Instruction-Pointer, Segment }
- inst_off, { " , Offset }
- oper_seg, { Operand-Pointer , Segment }
- oper_off: Word; { " , Offset }
-
- inst_point : ^Word; { zum Adressieren des Opcodes }
-
- oper_point : Record
- Case Integer of { zum Adressieren des Operanden }
- 1 : (ex : ^Extended);
- 2 : (db : ^Double);
- 3 : (si : ^Single);
- 4 : (co : ^Comp);
- end;
-
- marker: Array [0..7] of Word; { Register-Marker nach Tag-Word }
-
- opt_dump, { soll ausgeben werden? }
- opt_exit, { soll aufgehoert werden? }
- opt_ask, { soll Ergebnis abgefragt werden? }
- opt_auto : Boolean; { soll Ergebnis automatisch korrigiert werden? }
-
- i : Integer;
-
- mem_access: Boolean; { gibt es Speicherzugriff? }
-
- op_name : String; { Mnemonik des Befehls }
-
- { Ersetze Stacktop durch abgefragten Wert }
- Procedure ask_correct;
- Var
- res : Extended;
- ch : Char;
- t : String;
- code : Integer;
- begin
- Asm
- fstp res
- end;
- WriteLN;
- Write('The result would be ', res, '. Change? (y/n) ' );
- Repeat
- Repeat Until KeyPressed;
- ch := ReadKey;;
- Until ch in ['Y','y','N','n'];
- Writeln;
- if ch in ['Y','y'] then
- Repeat
- Write('New value : ');
- READLN(t);
- VAL(t, res, code);
- Until code = 0;
- Asm
- fld res
- end;
- end;
-
- Function hex(w : Word) : String; { Ausgabe als HeX-Zahl }
- Const
- zif : Array [0..15] of Char = ('0','1','2','3','4','5','6','7','8','9',
- 'a','b','c','d','e','f');
- begin
- hex := zif[w div zweipot[12]] +
- zif[(w MOD zweipot[12]) div zweipot[8]] +
- zif[(w MOD zweipot[8]) div zweipot[4]] +
- zif[w MOD zweipot[4]];
- end;
-
- Procedure choice;
- Var
- ch : Char;
- begin
- WriteLN;
- Write('C)ontinue, A)bort ');
- Repeat
- Repeat Until KeyPressed;
- ch:=ReadKey;;
- if ch in ['A','a'] then
- Halt(0);
- Until ch in ['C','c'];
- WriteLN;
- end;
-
- Procedure showcopro; { Ausgeben des FSAVE - Records }
- Var
- i : Integer;
- begin
- TextMode(LastMode);
- HighVideo;
- WriteLN('Floating point exception, last opcode: ',hex(opcode),
- ' (',op_name,')');
- NormVideo;
- WriteLN('Instruction Pointer : ',hex(inst_seg),':',hex(inst_off),
- ' (',hex(inst_point^),')');
- if mem_access then
- begin
- WriteLN('Operand Pointer : ',hex(oper_seg),':',hex(oper_off));
- WriteLN('( Extended: ',oper_point.ex^,', Double: ',oper_point.db^);
- WriteLN(' Single : ',oper_point.si^,', Comp : ',oper_point.co^,' )');
- end
- else
- begin
- WriteLN;
- WriteLN ('No memory access');
- WriteLN;
- end;
- HighVideo;
- if (occured and stackfault) = 0 then
- begin
- WriteLN('Exception ','Masked':8,'Occured':8,'Should be masked':18);
- NormVideo;
- For i:=0 to 5 do
- WriteLN(ex_nam[i], (masked and zweipot[i]) <> 0 : 8,
- (occured and zweipot[i]) <> 0 : 8,
- (setmasks and zweipot[i]) <> 0 : 18);
- HighVideo;
- end
- else
- begin
- WriteLN('Invalid Operation:');
- if (copro.status_Word and con1) <> 0 then
- WriteLN(' -- Stack Overflow --')
- else
- WriteLN(' -- Stack Underflow --');
- WriteLN;
- end;
-
- WriteLN('Reg ','Value':29,'Marked':10);
- Normvideo;
- For i := 0 to 7 do
- begin
- Write('st(',i,')', copro.st[i] : 29);
- Case marker[i] OF
- valid : WriteLN('Valid' : 10);
- spec : WriteLN('Special' : 10);
- empty : WriteLN('Empty' : 10);
- zero : WriteLN('Zero' : 10);
- end;
- end;
- end;
-
- { Ersetze Stacktop durch Auto-Korrekt-Wert }
-
- Procedure auto_corr;
- Var
- res : Extended;
- i : Integer;
- begin
- Asm
- fstp res
- end;
- For i := 0 to 5 do
- if ((occured and zweipot[i]) <> 0) and
- ((auto_on and zweipot[i]) <> 0) then
- res := auto_val[i];
- Asm
- fld res
- end;
- end;
-
-
- Procedure do_it_again;
- Type
- codearr = Array[0..4] of Byte;
- Var
- sam : Record
- Case Boolean OF
- True : (b: ^codearr );
- False: (p: Procedure);
- end;
-
- op_point : Pointer;
- x : extended;
- begin
- New(sam.b);
- sam.b^[0]:=Hi(opcode);
- sam.b^[1]:=Lo(opcode);
- if mem_access then
- begin
- { --- mod r/m auf ds:[di] stellen (00ttt101) --- }
- sam.b^[1] := sam.b^[1] and not (zweipot[7] + zweipot[6] + zweipot[1]);
- sam.b^[1] := sam.b^[1] or (zweipot[2] + zweipot[0]);
- end;
- sam.b^[2] := $ca; { retf 0000 }
- sam.b^[3] := $00;
- sam.b^[4] := $00;
- op_point := oper_point.ex;
- Asm
- push ds
- lds di, op_point
- end;
-
- sam.p;
-
- Asm
- pop ds
- end;
- Dispose(sam.b);
- end;
-
- begin
- Asm
- push ax
- xor al,al
- out 0f0h,al
- mov al,020h
- out 0a0h,al
- out 020h,al
- pop ax
- fsave copro
- end;
-
- { === Pruefen, ob Bearbeitung durch ERRORCON erwuenscht === }
- if (copro.status_Word and standard) <> 0 then
- begin
- Asm
- frstor copro
- end;
- normal.pro; { Bye, bye ... }
- end;
- { === Auswerten des FSAVE-Records ========================= }
- { --- Opcode wie im Copro gespeichert --- }
- opcode := zweipot[15] + zweipot[14] + zweipot[12] + zweipot[11] +
- (copro.ip MOD zweipot[11]);
- op_name := dis(opcode);
- mem_access := op_name='...';
- { --- Was war maskiert, was ist passiert? --- }
- masked := Lo(copro.control_Word);
- occured := Lo(copro.status_Word );
- { --- Der Instruction-Pointer --- }
- inst_seg := copro.ip and (zweipot[15] + zweipot[14] + zweipot[13] +
- zweipot[12]);
- inst_off := copro.instruction_Pointer;
- inst_point := Ptr(inst_seg,inst_off);
- { --- Der Operand-Pointer --- }
- oper_seg := copro.op and (zweipot[15] + zweipot[14] + zweipot[13] +
- zweipot[12]);
- oper_off := copro.operand_Pointer;
- oper_point.ex := Ptr(oper_seg,oper_off);
- { --- Wer ist gerade Stacktop? --- }
- top := (copro.status_Word and topmask) div topdiv;
- { --- Einlesen der Marker aus Tag-Word --- }
- For i := 0 to 7 do
- begin
- marker[(8 + i - top) MOD 8] := (copro.tag_Word and (zweipot[i * 2] +
- zweipot[i * 2 + 1])) div zweipot[i * 2];
- end;
-
- { --- Welche Aktionen sollen ausgefuehrt werden? --- }
- opt_dump := (copro.status_Word and dump_on) <> 0;
- opt_exit := (copro.status_Word and Exit_on) <> 0;
- opt_ask := (copro.status_Word and ask_on ) <> 0;
- opt_auto := (copro.status_Word and auto_on) <> 0;
-
- { === Aktionen ============================================ }
- if opt_dump then
- showcopro;
- if opt_exit then
- begin
- WriteLN;
- WriteLN('Exit Program due to Programmers request');
- HALT; { Bye, bye ... }
- end;
- if opt_dump and not (opt_ask) then
- choice;
-
- copro.control_Word := copro.control_Word or anyerrors;
- Asm
- frstor copro
- fclex
- end;
- { --- Befehl nochmals ausfuehren --- }
- if (occured and do_again) <> 0 then
- do_it_again;
- { --- Noch was? --- }
- if opt_auto then
- auto_corr;
- if opt_ask then
- ask_correct;
- restore_masks;
- end;
-
- { ------------- Ein- und Ausschalten ------------- }
-
- Procedure handle_on;
- begin
- Getintvec($75, normal.adr);
- Setintvec($75, @errorcon);
- end;
-
- Procedure handle_off;
- begin
- Setintvec($75, normal.adr);
- end;
-
- begin
- handle_on;
- dump_on :=0;
- Exit_on :=0;
- ask_on :=0;
- auto_on :=0;
- standard:=0;
- do_again:=invalid+zero_div+denormal;
- clear_copro;
- end.
-
-
-
-
-
-
- Unit dis387;
-
- Interface
-
- Function dis(opco : Word) : String;
-
- Implementation
-
- Function dis;
- Var
- d, op : String;
-
- Procedure opcr(st : Word);
- Var
- t : String;
- begin
- str(st, t);
- op := ' st,st(' + t + ')';
- end;
-
- Procedure opc(st : Word);
- Var
- t : String;
- begin
- str(st, t);
- op := ' st(' + t + '),st';
- end;
-
- Procedure op1(st : Word);
- Var
- t : String;
- begin
- str(st, t);
- op := ' st(' + t + ')';
- end;
-
- begin
- d := '...';
- op := '';
-
- Case Hi(opco) OF
- $d8 :
- Case Lo(opco) div 16 OF
- $c :
- if opco MOD 16 >= 8 then
- begin
- d := 'fmul';
- opcr(opco MOD 16 - 8);
- end
- else
- begin
- d := 'fadd';
- opcr(opco MOD 16);
- end;
-
- $e :
- if opco MOD 16 >= 8 then
- begin
- d := 'fsubr';
- opcr(opco MOD 16 - 8);
- end
- else
- begin
- d := 'fsub';
- opcr(opco MOD 16);
- end;
-
- $f :
- if opco MOD 16 >= 8 then
- begin
- d := 'fdivr';
- opcr(opco MOD 16 - 8);
- end
- else
- begin
- d := 'fdiv';
- opcr(opco MOD 16);
- end;
- end;
-
- $d9 :
- Case Lo(opco) OF
- $d0 : d := 'fnop';
- $e0 : d := 'fchs';
- $e1 : d := 'fabs';
- $e4 : d := 'ftst';
- $e5 : d := 'fxam';
- $e8 : d := 'fld1';
- $e9 : d := 'fld2t';
- $ea : d := 'fld2e';
- $eb : d := 'fldpi';
- $ec : d := 'fldlg2';
- $ed : d := 'fldln2';
- $ee : d := 'fldz';
- $f0 : d := 'f2xm1';
- $f1 : d := 'fyl2x';
- $f2 : d := 'fptan';
- $f3 : d := 'fpatan';
- $f4 : d := 'fxtract';
- $f5 : d := 'fprem1';
- $f6 : d := 'fdecstp';
- $f7 : d := 'fincstp';
- $f8 : d := 'fprem';
- $f9 : d := 'fyl2xp1';
- $fa : d := 'fsqrt';
- $fb : d := 'fsincos';
- $fc : d := 'frndint';
- $fd : d := 'fscale';
- $fe : d := 'fsin';
- $ff : d := 'fcos';
- end;
-
- $db :
- Case Lo(opco) OF
- $e2 : d := 'fclex';
- $e3 : d := 'finit';
- end;
- $dc :
- Case Lo(opco) div 16 OF
- $c :
- if opco MOD 16 >= 8 then
- begin
- d := 'fmul';
- opc(opco MOD 16-8);
- end
- else
- begin
- d := 'fadd';
- opc(opco MOD 16);
- end;
-
- $e : if opco MOD 16 >= 8 then
- begin
- d := 'fsub';
- opc(opco MOD 16 - 8);
- end
- else
- begin
- d := 'fsubr';
- opc(opco MOD 16);
- end;
-
- $f :
- if opco MOD 16 >= 8 then
- begin
- d := 'fdiv';
- opc(opco MOD 16 - 8);
- end
- else
- begin
- d := 'fdivr';
- opc(opco MOD 16);
- end;
- end;
-
- $dd :
- Case Lo(opco) div 16 OF
- $c :
- begin
- d := 'ffree';
- op1(opco MOD 16);
- end;
- $d :
- if opco MOD 16 >= 8 then
- begin
- d := 'fstp';
- op1(opco MOD 16 - 8);
- end
- else
- begin
- d := 'fst';
- op1(opco MOD 16);
- end;
- $e :
- if opco MOD 16 >= 8 then
- begin
- d := 'fucomp';
- op1(opco MOD 16 - 8);
- end
- else
- begin
- d := 'fucom';
- op1(opco MOD 16);
- end;
- end;
-
- $de :
- Case Lo(opco) div 16 OF
- $c :
- if opco MOD 16 >= 8 then
- begin
- d := 'fmulp';
- opc(opco MOD 16 - 8);
- end
- else
- begin
- d := 'faddp';
- opc(opco MOD 16);
- end;
-
- $d : d := 'fcompp';
-
- $e :
- if opco MOD 16 >= 8 then
- begin
- d := 'fsubp';
- opc(opco MOD 16 - 8);
- end
- else
- begin
- d := 'fsubrp';
- opc(opco MOD 16);
- end;
-
- $f :
- if opco MOD 16 >= 8 then
- begin
- d := 'fdivp';
- opc(opco MOD 16 - 8);
- end
- else
- begin
- d := 'fdivrp';
- opc(opco MOD 16);
- end;
- end;
- end;
-
- dis := d + op;
- end;
-
- begin
- end.